home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / srcuc.zip / PROSPROC.C < prev    next >
C/C++ Source or Header  |  1992-03-27  |  14KB  |  395 lines

  1. /* -*-C-*-
  2.  
  3. $Header: /usr/local/scheme/src/microcode/RCS/prosproc.c,v 1.12 1992/03/27 20:32:53 cph Exp $
  4.  
  5. Copyright (c) 1990-92 Massachusetts Institute of Technology
  6.  
  7. This material was developed by the Scheme project at the Massachusetts
  8. Institute of Technology, Department of Electrical Engineering and
  9. Computer Science.  Permission to copy this software, to redistribute
  10. it, and to use it for any purpose is granted, subject to the following
  11. restrictions and understandings.
  12.  
  13. 1. Any copy made of this software must include this copyright notice
  14. in full.
  15.  
  16. 2. Users of this software agree to make their best efforts (a) to
  17. return to the MIT Scheme project any improvements or extensions that
  18. they make, so that these may be included in future releases; and (b)
  19. to inform MIT of noteworthy uses of this software.
  20.  
  21. 3. All materials developed as a consequence of the use of this
  22. software shall duly acknowledge such use, in accordance with the usual
  23. standards of acknowledging credit in academic research.
  24.  
  25. 4. MIT has made no warrantee or representation that the operation of
  26. this software will be error-free, and MIT is under no obligation to
  27. provide any services, by way of maintenance, update, or otherwise.
  28.  
  29. 5. In conjunction with products arising from the use of this material,
  30. there shall be no use of the name of the Massachusetts Institute of
  31. Technology nor of any adaptation thereof in any advertising,
  32. promotional, or sales literature without prior written consent from
  33. MIT in each case. */
  34.  
  35. /* Primitives for subprocess control. */
  36.  
  37. #include "scheme.h"
  38. #include "prims.h"
  39. #include "osproc.h"
  40.  
  41. extern Tchannel EXFUN (arg_channel, (int));
  42. static int EXFUN (string_vector_p, (SCHEME_OBJECT vector));
  43. static char ** EXFUN (convert_string_vector, (SCHEME_OBJECT vector));
  44.  
  45. static Tprocess
  46. DEFUN (arg_process, (argument_number), int argument_number)
  47. {
  48.   Tprocess process =
  49.     (arg_index_integer (argument_number, OS_process_table_size));
  50.   if (! (OS_process_valid_p (process)))
  51.     error_bad_range_arg (argument_number);
  52.   return (process);
  53. }
  54.  
  55. #define PROCESS_CHANNEL_ARG(arg, type, channel)                \
  56. {                                    \
  57.   if ((ARG_REF (arg)) == SHARP_F)                    \
  58.     (type) = process_channel_type_none;                    \
  59.   else if ((ARG_REF (arg)) == (LONG_TO_FIXNUM (-1)))            \
  60.     (type) = process_channel_type_inherit;                \
  61.   else if ((ARG_REF (arg)) == (LONG_TO_FIXNUM (-2)))            \
  62.     {                                    \
  63.       if (ctty_type != process_ctty_type_explicit)            \
  64.     error_bad_range_arg (arg);                    \
  65.       (type) = process_channel_type_ctty;                \
  66.     }                                    \
  67.   else                                    \
  68.     {                                    \
  69.       (type) = process_channel_type_explicit;                \
  70.       (channel) = (arg_channel (arg));                    \
  71.     }                                    \
  72. }
  73.  
  74. DEFINE_PRIMITIVE ("MAKE-SUBPROCESS", Prim_make_subprocess, 7, 7,
  75.   "Create a subprocess.\n\
  76. First arg FILENAME is the program to run.\n\
  77. Second arg ARGV is a vector of strings to pass to the program as arguments.\n\
  78. Third arg ENV is a vector of strings to pass as the program's environment;\n\
  79.   #F means inherit Scheme's environment.\n\
  80. Fourth arg CTTY specifies the program's controlling terminal:\n\
  81.   #F means none;\n\
  82.   -1 means use Scheme's controlling terminal in background;\n\
  83.   -2 means use Scheme's controlling terminal in foreground;\n\
  84.   string means open that terminal.\n\
  85. Fifth arg STDIN is the input channel for the subprocess.\n\
  86. Sixth arg STDOUT is the output channel for the subprocess.\n\
  87. Seventh arg STDERR is the error channel for the subprocess.\n\
  88.   Each channel arg can take these values:\n\
  89.   #F means none;\n\
  90.   -1 means use the corresponding channel from Scheme;\n\
  91.   -2 means use the controlling terminal (valid only when CTTY is a string);\n\
  92.   otherwise the argument must be a channel.")
  93. {
  94.   PRIMITIVE_HEADER (7);
  95.   CHECK_ARG (2, string_vector_p);
  96.   {
  97.     PTR position = dstack_position;
  98.     CONST char * filename = (STRING_ARG (1));
  99.     char * CONST * argv =
  100.       ((char * CONST *) (convert_string_vector (ARG_REF (2))));
  101.     SCHEME_OBJECT env_object = (ARG_REF (3));
  102.     char * CONST * env = 0;
  103.     CONST char * working_directory = 0;
  104.     enum process_ctty_type ctty_type;
  105.     char * ctty_name = 0;
  106.     enum process_channel_type channel_in_type;
  107.     Tchannel channel_in;
  108.     enum process_channel_type channel_out_type;
  109.     Tchannel channel_out;
  110.     enum process_channel_type channel_err_type;
  111.     Tchannel channel_err;
  112.  
  113.     if ((PAIR_P (env_object)) && (STRING_P (PAIR_CDR (env_object))))
  114.       {
  115.     working_directory =
  116.       ((CONST char *) (STRING_LOC ((PAIR_CDR (env_object)), 0)));
  117.     env_object = (PAIR_CAR (env_object));
  118.       }
  119.     if (env_object != SHARP_F)
  120.       {
  121.     if (! (string_vector_p (env_object)))
  122.       error_wrong_type_arg (3);
  123.     env = ((char * CONST *) (convert_string_vector (env_object)));
  124.       }
  125.     if ((ARG_REF (4)) == SHARP_F)
  126.       ctty_type = process_ctty_type_none;
  127.     else if ((ARG_REF (4)) == (LONG_TO_FIXNUM (-1)))
  128.       ctty_type = process_ctty_type_inherit_bg;
  129.     else if ((ARG_REF (4)) == (LONG_TO_FIXNUM (-2)))
  130.       ctty_type = process_ctty_type_inherit_fg;
  131.     else
  132.       {
  133.     ctty_type = process_ctty_type_explicit;
  134.     ctty_name = (STRING_ARG (4));
  135.       }
  136.     PROCESS_CHANNEL_ARG (5, channel_in_type, channel_in);
  137.     PROCESS_CHANNEL_ARG (6, channel_out_type, channel_out);
  138.     PROCESS_CHANNEL_ARG (7, channel_err_type, channel_err);
  139.     {
  140.       Tprocess process =
  141.     (OS_make_subprocess
  142.      (filename, argv, env, working_directory,
  143.       ctty_type, ctty_name,
  144.       channel_in_type, channel_in,
  145.       channel_out_type, channel_out,
  146.       channel_err_type, channel_err));
  147.       dstack_set_position (position);
  148.       PRIMITIVE_RETURN (long_to_integer (process));
  149.     }
  150.   }
  151. }
  152.  
  153. static int
  154. DEFUN (string_vector_p, (vector), SCHEME_OBJECT vector)
  155. {
  156.   if (! (VECTOR_P (vector)))
  157.     return (0);
  158.   {
  159.     unsigned long length = (VECTOR_LENGTH (vector));
  160.     SCHEME_OBJECT * scan = (VECTOR_LOC (vector, 0));
  161.     SCHEME_OBJECT * end = (scan + length);
  162.     while (scan < end)
  163.       if (! (STRING_P (*scan++)))
  164.     return (0);
  165.   }
  166.   return (1);
  167. }
  168.  
  169. static char **
  170. DEFUN (convert_string_vector, (vector), SCHEME_OBJECT vector)
  171. {
  172.   unsigned long length = (VECTOR_LENGTH (vector));
  173.   char ** result = (dstack_alloc ((length + 1) * (sizeof (char *))));
  174.   SCHEME_OBJECT * scan = (VECTOR_LOC (vector, 0));
  175.   SCHEME_OBJECT * end = (scan + length);
  176.   char ** scan_result = result;
  177.   while (scan < end)
  178.     (*scan_result++) = ((char *) (STRING_LOC ((*scan++), 0)));
  179.   (*scan_result) = 0;
  180.   return (result);
  181. }
  182.  
  183. DEFINE_PRIMITIVE ("SCHEME-ENVIRONMENT", Prim_scheme_environment, 0, 0, 0)
  184. {
  185.   PRIMITIVE_HEADER (0);
  186.   {
  187.     extern char ** environ;
  188.     {
  189.       char ** scan_environ = environ;
  190.       char ** end_environ = scan_environ;
  191.       while ((*end_environ++) != 0) ;
  192.       end_environ -= 1;
  193.       {
  194.     SCHEME_OBJECT result =
  195.       (allocate_marked_vector (TC_VECTOR, (end_environ - environ), 1));
  196.     SCHEME_OBJECT * scan_result = (VECTOR_LOC (result, 0));
  197.     while (scan_environ < end_environ)
  198.       (*scan_result++) =
  199.         (char_pointer_to_string ((unsigned char *) (*scan_environ++)));
  200.     PRIMITIVE_RETURN (result);
  201.       }
  202.     }
  203.   }
  204. }
  205.  
  206. DEFINE_PRIMITIVE ("PROCESS-DELETE", Prim_process_delete, 1, 1,
  207.   "Delete process PROCESS-NUMBER from the process table.")
  208. {
  209.   PRIMITIVE_HEADER (1);
  210.   OS_process_deallocate (arg_process (1));
  211.   PRIMITIVE_RETURN (UNSPECIFIC);
  212. }
  213.  
  214. DEFINE_PRIMITIVE ("PROCESS-TABLE", Prim_process_table, 0, 0,
  215.   "Return a vector of all processes in the process table.")
  216. {
  217.   PRIMITIVE_HEADER (0);
  218.   {
  219.     Tprocess process;
  220.     for (process = 0; (process < OS_process_table_size); process += 1)
  221.       if (OS_process_valid_p (process))
  222.     obstack_grow ((&scratch_obstack), (&process), (sizeof (Tprocess)));
  223.   }
  224.   {
  225.     unsigned int n_processes =
  226.       ((obstack_object_size ((&scratch_obstack))) / (sizeof (Tprocess)));
  227.     if (n_processes == 0)
  228.       PRIMITIVE_RETURN (SHARP_F);
  229.     {
  230.       Tprocess * processes = (obstack_finish (&scratch_obstack));
  231.       Tprocess * scan_processes = processes;
  232.       SCHEME_OBJECT vector =
  233.     (allocate_marked_vector (TC_VECTOR, n_processes, 1));
  234.       SCHEME_OBJECT * scan_vector = (VECTOR_LOC (vector, 0));
  235.       SCHEME_OBJECT * end_vector = (scan_vector + n_processes);
  236.       while (scan_vector < end_vector)
  237.     (*scan_vector++) = (long_to_integer (*scan_processes++));
  238.       obstack_free ((&scratch_obstack), processes);
  239.       PRIMITIVE_RETURN (vector);
  240.     }
  241.   }
  242. }
  243.  
  244. DEFINE_PRIMITIVE ("PROCESS-ID", Prim_process_id, 1, 1, 
  245.   "Return the process ID of process PROCESS-NUMBER.")
  246. {
  247.   PRIMITIVE_HEADER (1);
  248.   PRIMITIVE_RETURN (long_to_integer (OS_process_id (arg_process (1))));
  249. }
  250.  
  251. DEFINE_PRIMITIVE ("PROCESS-JOB-CONTROL-STATUS", Prim_process_jc_status, 1, 1, 
  252.   "Returns the job-control status of process PROCESS-NUMBER:\n\
  253.   0 means this system doesn't support job control.\n\
  254.   1 means the process doesn't have the same controlling terminal as Scheme.\n\
  255.   2 means it's the same ctty but the OS doesn't have job control.\n\
  256.   3 means it's the same ctty and the OS has job control.")
  257. {
  258.   PRIMITIVE_HEADER (1);
  259.   switch (OS_process_jc_status (arg_process (1)))
  260.     {
  261.     case process_jc_status_no_ctty:
  262.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (0));
  263.     case process_jc_status_unrelated:
  264.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (1));
  265.     case process_jc_status_no_jc:
  266.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (2));
  267.     case process_jc_status_jc:
  268.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (3));
  269.     default:
  270.       error_bad_range_arg (1);
  271.       PRIMITIVE_RETURN (UNSPECIFIC);
  272.     }
  273. }
  274.  
  275. DEFINE_PRIMITIVE ("PROCESS-STATUS-SYNC", Prim_process_status_sync, 1, 1,
  276.   "Synchronize the status of process PROCESS-NUMBER.\n\
  277. Return #F if it was previously synchronized, #T if not.")
  278. {
  279.   PRIMITIVE_HEADER (1);
  280.   PRIMITIVE_RETURN
  281.     (BOOLEAN_TO_OBJECT (OS_process_status_sync (arg_process (1))));
  282. }
  283.  
  284. DEFINE_PRIMITIVE ("PROCESS-STATUS-SYNC-ALL", Prim_process_status_sync_all, 0, 0, 0)
  285. {
  286.   PRIMITIVE_HEADER (0);
  287.   PRIMITIVE_RETURN (BOOLEAN_TO_OBJECT (OS_process_status_sync_all ()));
  288. }
  289.  
  290. DEFINE_PRIMITIVE ("PROCESS-STATUS", Prim_process_status, 1, 1,
  291.   "Return the status of process PROCESS-NUMBER, a nonnegative integer:\n\
  292.   0 = running; 1 = stopped; 2 = exited; 3 = signalled.\n\
  293. The value is from the last synchronization.")
  294. {
  295.   PRIMITIVE_HEADER (1);
  296.   switch (OS_process_status (arg_process (1)))
  297.     {
  298.     case process_status_running:
  299.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (0));
  300.     case process_status_stopped:
  301.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (1));
  302.     case process_status_exited:
  303.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (2));
  304.     case process_status_signalled:
  305.       PRIMITIVE_RETURN (LONG_TO_UNSIGNED_FIXNUM (3));
  306.     default:
  307.       error_external_return ();
  308.       PRIMITIVE_RETURN (UNSPECIFIC);
  309.     }
  310. }
  311.  
  312. DEFINE_PRIMITIVE ("PROCESS-REASON", Prim_process_reason, 1, 1, 
  313.   "Return the termination reason of process PROCESS-NUMBER.\n\
  314. This is a nonnegative integer, which depends on the process's status:\n\
  315.   running => zero;\n\
  316.   stopped => the signal that stopped the process;\n\
  317.   exited => the exit code returned by the process;\n\
  318.   signalled => the signal that killed the process.\n\
  319. The value is from the last synchronization.")
  320. {
  321.   PRIMITIVE_HEADER (1);
  322.   PRIMITIVE_RETURN (long_to_integer (OS_process_reason (arg_process (1))));
  323. }
  324.  
  325. DEFINE_PRIMITIVE ("PROCESS-SIGNAL", Prim_process_signal, 2, 2,
  326.   "Send a signal to process PROCESS-NUMBER; second arg SIGNAL says which one.")
  327. {
  328.   PRIMITIVE_HEADER (2);
  329.   OS_process_send_signal ((arg_process (1)), (arg_nonnegative_integer (2)));
  330.   PRIMITIVE_RETURN (UNSPECIFIC);
  331. }
  332.  
  333. #define PROCESS_SIGNALLING_PRIMITIVE(signaller)                \
  334. {                                    \
  335.   PRIMITIVE_HEADER (1);                            \
  336.   signaller (arg_process (1));                        \
  337.   PRIMITIVE_RETURN (UNSPECIFIC);                    \
  338. }
  339.  
  340. DEFINE_PRIMITIVE ("PROCESS-KILL", Prim_process_kill, 1, 1,
  341.   "Kills process PROCESS-NUMBER (unix SIGKILL).")
  342.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_kill)
  343.  
  344. DEFINE_PRIMITIVE ("PROCESS-INTERRUPT", Prim_process_interrupt, 1, 1,
  345.   "Interrupts process PROCESS-NUMBER (unix SIGINT).")
  346.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_interrupt)
  347.  
  348. DEFINE_PRIMITIVE ("PROCESS-QUIT", Prim_process_quit, 1, 1,
  349.   "Sends the quit signal to process PROCESS-NUMBER (unix SIGQUIT).")
  350.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_quit)
  351.  
  352. DEFINE_PRIMITIVE ("PROCESS-HANGUP", Prim_process_hangup, 1, 1,
  353.   "Sends the hangup signal to process PROCESS-NUMBER (unix SIGHUP).")
  354.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_hangup)
  355.  
  356. DEFINE_PRIMITIVE ("PROCESS-STOP", Prim_process_stop, 1, 1,
  357.   "Stops process PROCESS-NUMBER (unix SIGTSTP).")
  358.      PROCESS_SIGNALLING_PRIMITIVE (OS_process_stop)
  359.  
  360. DEFINE_PRIMITIVE ("PROCESS-CONTINUE-BACKGROUND", Prim_process_continue_background, 1, 1,
  361.   "Continues process PROCESS-NUMBER in the background.")
  362. {
  363.   PRIMITIVE_HEADER (1);
  364.   {
  365.     Tprocess process = (arg_process (1));
  366.     if (! (OS_process_continuable_p (process)))
  367.       error_bad_range_arg (1);
  368.     OS_process_continue_background (process);
  369.   }
  370.   PRIMITIVE_RETURN (UNSPECIFIC);
  371. }
  372.  
  373. DEFINE_PRIMITIVE ("PROCESS-WAIT", Prim_process_wait, 1, 1,
  374.   "Waits until process PROCESS-NUMBER is not running.")
  375. {
  376.   PRIMITIVE_HEADER (1);
  377.   OS_process_wait (arg_process (1));
  378.   PRIMITIVE_RETURN (UNSPECIFIC);
  379. }
  380.  
  381. DEFINE_PRIMITIVE ("PROCESS-CONTINUE-FOREGROUND", Prim_process_continue_foreground, 1, 1,
  382.   "Continues process PROCESS-NUMBER in the foreground.\n\
  383. The process must have the same controlling terminal as Scheme.")
  384. {
  385.   PRIMITIVE_HEADER (1);
  386.   {
  387.     Tprocess process = (arg_process (1));
  388.     if (! ((OS_process_foregroundable_p (process))
  389.        && (OS_process_continuable_p (process))))
  390.       error_bad_range_arg (1);
  391.     OS_process_continue_foreground (process);
  392.     PRIMITIVE_RETURN (UNSPECIFIC);
  393.   }
  394. }
  395.